<?php
/**
 * Api para administrar los tickets de pre-pago
 *
 * Esta clase implementa la api par administrar los tickets de pre-pago.
 * Los tickets se crean con algun valor y se pueden consumir completamente (no se puede consumir parte de un ticket).
 * Cada ticket tiene un estado que depende de lo que le haya ocurrido, a groso modo un ticket se crea y despues se
 * consume, invalida o borra (el borrado es una operacion de uso interno y no deberia utilizarse regularmente).
 * Un ticket tambien tiene una fecha de expiracion y su estado puede pasar a expirado.
 *
 */
class PrepaidWS_Service_Main extends Ext_Services
{
    // SEE PACKAGE PK_PREPAID
    const g_USED    = 'U';
    const g_ACTIVE  = 'A';
    const g_VOID    = 'V';
    const g_EXPIRED = 'E';
    const g_DNE     = 'N';

    private $_plSqlModel;

    function __construct() {
        // @todo: usar el db adecuado !!!
        $db = Zend_Db_Table::getDefaultAdapter();
        $this->_plSqlModel = new Ext_Model_PLSqlProcedure( $db );
        $this->_plSqlModel->setPackage('ppc_prepaid_pk');
    }

    /**
     * Crea un ticke de prepago
     *
     * Crea un ticket de cierto valor. Queda registrado un codigo externo y un nombre del sistema de origen que
     * sirven para identificar al que creo el ticker. El ticket tiene un afecha de expiracion definida
     * en meses a partir de la fecha de creacion si no se consume antes entonces queda vencido y ya no se puede consumir.
     *
     * @param integer $userId id del usuario a validar con la credencial.
     * @param string $credential credencial del usuario.
     * @param integer $value valor monetario del ticket
     * @param integer $sourceObjectId id externo para identificar quien creo el ticket.
     * @param string $sourceObjectCode codigo del sistema que esta creando el ticket.
     * @param integer $monthExpiration fecha de vencimiento del ticket en meses a partir de la fecha de creacion.
     * @return string codigo del ticket de prepago.
     */
    function createCode( $userId, $credential, $value, $sourceObjectId, $sourceObjectCode, $monthExpiration ) {
        $this->_validateCredential($userId, $credential);
        if (! is_numeric( $value ) ) {
            throw new Ext_Exception("createCode invalid parameter value not numeric");
        }
        if (! is_numeric( $sourceObjectId ) ) {
            throw new Ext_Exception("createCode invalid parameter sourceObject not numeric");
        }
        if (! is_numeric( $monthExpiration ) ) {
            throw new Ext_Exception("createCode invalid parameter montExpiration not numeric");
        }
        if ( strlen($sourceObjectCode) > 20 ) {
            throw new Ext_Exception("createCode invalid parameter sourceObjectCode len > 20");
        }
        $r_code = str_pad( "", 21 );

        try {
            $this->_plSqlModel->create_code( array( "p_value" => $value,
                                                 "r_code"  => &$r_code,
                                                 "p_source_object_id" => $sourceObjectId,
                                                 "p_source_object_code" =>$sourceObjectCode,
                                                 "p_expiration_months" => $monthExpiration
                ));
        } catch ( Exception $e ) {
            throw new Exception( $e->__toString() . " " . $e->getMessage() );
        }
        return $r_code;
    }

    /**
     * Consume un ticked de pre-pago.
     *
     * Consume un ticket de prepago. Se deja registro del sistema que consumio el ticket (a partir de un codigo)
     * y un identificador externo que identifica a quien lo consumio.
     *
     * @param integer $userId id del usuario a validar con la credencial.
     * @param string $credential credencial del usuario.
     * @param string $code codigo del pre-pago a consumir.
     * @param integer $destinationObjectId id externo que identifica a quien consumio el ticket.
     * @param string $destinationObjectCode codigo que identifica al sistema que lleva registro del id de quien consumio el ticket.
     * @return boolean true si el ticket fue consumido
     */
    function consume( $userId, $credential, $code, $destinationObjectId, $destinationObjectCode ) {
        $this->_validateCredential($userId, $credential);
        if ( strlen($code) > 20 ) {
            throw new Ext_Exception("createCode invalid parameter code len > 20");
        }
        if (! is_numeric( $destinationObjectId ) ) {
            throw new Ext_Exception("createCode invalid parameter destinationObject not numeric");
        }
        if ( strlen($destinationObjectCode) > 20 ) {
            throw new Ext_Exception("createCode invalid parameter destinationObjectCode len > 20");
        }
        try {
            $retval = 0; // buffer
            $this->_plSqlModel->consume( array( "p_code" => $code,
                                                 "p_destination_object_id" => $destinationObjectId,
                                                 "p_destination_object_code" => $destinationObjectCode,
                                                 "r_retval" => &$retval
                ));
        } catch ( Exception $e ) {
            throw new Exception( $e->__toString() . " " . $e->getMessage() );
        }
        return ( intval( $retval ) != 0 );
    }

    /**
     * Devuelve el estado de un ticket.
     *
     * Devuelve un vector con tres valores: el valor monetario del ticket, el id interno del ticket y el estado del ticket
     * que puede ser U (usado), A (activo), V (revocado, void), E (vencido, expired).
     *
     * @param integer $userId id del usuario a validar con la credencial.
     * @param string $credential credencial del usuario.
     * @param string $code codigo del pre-pago.
     * @return array valor del ticket, id del ticket, estado
     */
    function getStatus( $userId, $credential, $code ) {
        $this->_validateCredential($userId, $credential);
        if ( strlen($code) > 20 ) {
            throw new Ext_Exception("createCode invalid parameter code len > 20");
        }
        $r_value = str_pad( "", 21 );
        $r_valid = str_pad( "", 21 );
        $r_id    = str_pad( "", 21 );
        try {
            $this->_plSqlModel->get_Status( array( "p_code" => $code,
                                                   "r_value" => &$r_value,
                                                   "r_valid" => &$r_valid,
                                                   "r_id" => &$r_id,
                ));
        } catch ( Exception $e ) {
            throw new Exception( $e->__toString() . " " . $e->getMessage() );
        }
        if ( $r_valid == self::g_DNE ) {
            throw new Ext_Exception( "Code don't exists" );
        }
        return array("r_value" => &$r_value,
                     "r_valid" => &$r_valid,
                     "r_id" => &$r_id );
    }

    /**
     * Revoca un ticket basado en el codigo del sistema externo.
     *
     * Cambia el estado de un ticket a revocado basado en el codigo del sistema que creo el ticket
     * y el identificador externo en ese sistema de quien creo el ticket.
     *
     * @param integer $userId id del usuario a validar con la credencial.
     * @param string $credential credencial del usuario.
     * @param integer $sourceObjectId id externo que identifica a quien creo el ticket.
     * @param string $sourceObjectCode identificador del sistema que creo el ticket.
     * @return boolean devuleve siempre true.
     */
    function voidWithSource( $userId, $credential, $sourceObjectId, $sourceObjectCode ) {
        $this->_validateCredential($userId, $credential);
        if (! is_numeric( $sourceObjectId ) ) {
            throw new Ext_Exception("createCode invalid parameter sourceObject not numeric");
        }
        if ( strlen($sourceObjectCode) > 20 ) {
            throw new Ext_Exception("createCode invalid parameter sourceObjectCode len > 20");
        }

        try {
            $this->_plSqlModel->void_with_source( array( "p_source_object_id" => $sourceObjectId,
                                                         "p_source_object_code" =>$sourceObjectCode
                ));
        } catch ( Exception $e ) {
            throw new Exception( $e->__toString() . " " . $e->getMessage() );
        }
        // @todo: modificar el package para que me devuelva el estado.
        return true;
    }

    /**
     * Revoca un ticket.
     *
     * Cambia el estado de un ticket a revocado.
     *
     * @param integer $userId id del usuario a validar con la credencial.
     * @param string $credential credencial del usuario.
     * @param string $code codigo del pre-pago.
     * @return boolean devuelve siempre true
     */
    function voidWithCode( $userId, $credential, $code ) {
        $this->_validateCredential($userId, $credential);
        if ( strlen($code) > 20 ) {
            throw new Ext_Exception("createCode invalid parameter code len > 20");
        }
        try {
            $this->_plSqlModel->void_with_code( array( "p_code" => $code ) );
        } catch ( Exception $e ) {
            throw new Exception( $e->__toString() . " " . $e->getMessage() );
        }
        // @todo: modificar el package para que me devuelva el estado.
        return true;
    }

    /**
     * Borra un ticket basado en el codigo del sistema externo.
     *
     * Borra el ticket basado en el codigo del sistema que creo el ticket
     * y el identificador externo en ese sistema de quien creo el ticket.
     * Esta es una operacion interna y no debe ser utilizada regularmente.
     *
     * @param integer $userId id del usuario a validar con la credencial.
     * @param string $credential credencial del usuario.
     * @param integer $sourceObjectId id externo que identifica a quien creo el ticket.
     * @param string $sourceObjectCode identificador del sistema que creo el ticket.
     * @return boolean devuleve siempre true.
     */
    function dropWithSource( $userId, $credential, $sourceObjectId, $sourceObjectCode ) {
        $this->_validateCredential($userId, $credential);
        if (! is_numeric( $sourceObjectId ) ) {
            throw new Ext_Exception("createCode invalid parameter sourceObject not numeric");
        }
        if ( strlen($sourceObjectCode) > 20 ) {
            throw new Ext_Exception("createCode invalid parameter sourceObjectCode len > 20");
        }

        try {
            $this->_plSqlModel->drop_with_source( array( "p_source_object_id" => $sourceObjectId,
                                                         "p_source_object_code" =>$sourceObjectCode
                ));
        } catch ( Exception $e ) {
            throw new Exception( $e->__toString() . " " . $e->getMessage() );
        }
        // @todo: modificar el package para que me devuelva el estado.
        return true;
    }

    /**
     * Borra un ticket basado en el codigo del sistema externo.
     *
     * Borra un ticket, esta es una operacion interna y no debe ser utilizada regularmente.
     *
     * @param integer $userId id del usuario a validar con la credencial.
     * @param string $credential credencial del usuario.
     * @param string $code codigo del pre-pago.
     * @return boolean devuelve siempre true
     */
    function dropWithCode( $userId, $credential, $code ) {
        $this->_validateCredential($userId, $credential);
        if ( strlen($code) > 20 ) {
            throw new Ext_Exception("createCode invalid parameter code len > 20");
        }
        try {
            $this->_plSqlModel->drop_with_code( array( "p_code" => $code ) );
        } catch ( Exception $e ) {
            throw new Exception( $e->__toString() . " " . $e->getMessage() );
        }
        // @todo: modificar el package para que me devuelva el estado.
        return true;
    }
}
